global class ReservationDiscrepancyCheckBatch implements Database.Batchable<sObject>
{
    private String query = null;
    private ID scheduleId;
    
    global ReservationDiscrepancyCheckBatch(ID sId)
    {
    	scheduleId = sId;
        query = 'select id, Opportunity_Name__c from Productivity_Allocations__c where Reservation_and_Opp_Product_Difference__c != 0';
    }
    
    global Database.QueryLocator start(Database.BatchableContext bc)
    {
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext bc, List<sObject> scope)
    {
    	processProductivityAllocations(scope);
    }
    
    private void processProductivityAllocations(List<sObject> sObjectList)
    {
    	ID[] opportunityIDList = new ID[]{};
    	ID[] paIDList = new ID[]{};
    	
    	Map<ID, ID> paToOppMap = new Map<ID, ID>();
    	Map<ID, List<OpportunityLineItem>> oppToOliMap = new Map<ID, List<OpportunityLineItem>>();  
    	
    	Reservations__c[] addReservationsList = new Reservations__c[]{};
    	
    	Reservations__c r;
    	for(SObject sObj: sObjectList)
    	{
    		opportunityIDList.add((ID)sObj.get('Opportunity_Name__c'));
    		paIDList.add((ID)sObj.get('id'));
    		paToOppMap.put((ID)sObj.get('id'), (ID)sObj.get('Opportunity_Name__c'));	
    	}
    	
    	for(OpportunityLineItem[] oliList : [select id, opportunityid, pricebookentry.product2.id, Added_Value__c, End__c, Flex__c, Description, ListPrice, make_good__c, servicedate, UnitPrice, quantity, start__c, TotalPrice from opportunitylineitem where opportunityid in :opportunityidlist])
    	{
    		for(OpportunityLineItem oli: oliList)
    		{
    			OpportunityLineItem[] oliTempList = oppToOliMap.get(oli.opportunityid);  
    			if(oliTempList == null)
					oliTempList = new OpportunityLineItem[]{};
					
				oliTempList.add(oli);
				oppToOliMap.put(oli.opportunityid, oliTempList);
    		}
    	}
      	
    	for(Reservations__c[] delReservationsList : [select id from Reservations__c where Related_Productivity_Allocation__c in : paIDList])
    		delete delReservationsList;
    		
		for(ID paIdVal: paToOppMap.keyset())
		{   
			for(OpportunityLineItem oli: oppToOliMap.get(paToOppMap.get(paIdVal)))
			{				
				r = new Reservations__c(Related_Productivity_Allocation__c = paIdVal, Added_Value__c = oli.Added_Value__c, End__c = oli.End__c, Flex__c = oli.Flex__c, Line_Description__c = oli.Description, List_Price__c= oli.ListPrice, Make_Good__c = oli.make_good__c, Opportunity_Product_Date__c = oli.servicedate, Opportunity_Product_Sales_Price__c = oli.UnitPrice, Quantity__c = oli.quantity, Start__c = oli.start__c, Total_Price__c = oli.TotalPrice, Opportunity_Product__c = oli.pricebookentry.product2.id);
				addReservationsList.add(r);
			}
		}
		
		insert addReservationsList;
    }
    
    global void finish(Database.BatchableContext bc)
    {
 		CronTrigger ct = [SELECT Id FROM CronTrigger WHERE id = :scheduleId];
 		if(ct != null)    	
    		system.abortJob(ct.id);
    		
//        Datetime dt = Datetime.now().addHours(1);
        Datetime dt = Datetime.now().addMinutes(3);

        String sch = '0 '+dt.minute()+' '+dt.hour()+' '+dt.day()+' '+dt.month()+' '+' ? '+dt.year();
		ReservationDiscrepancyCheckScheduler  rdcs = new ReservationDiscrepancyCheckScheduler();
    	system.schedule('Reservation Scheduled '+sch, sch, rdcs);
    } 
}